package com.ymk.cmd;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.ymk.base.cmd.ACmd;
import com.ymk.base.cmd.CmdSign;
import com.ymk.base.exception.MallException;
import com.ymk.base.utlis.ParamsBuilder;
import com.ymk.bo.mch.MchBO;
import com.ymk.bo.member.MemberBO;
import com.ymk.bo.member.MemberFinanceLogBO;
import com.ymk.bo.orders.OrdersBO;
import com.ymk.bo.pay.PayDivideBO;
import com.ymk.bo.pay.PayPaymentBO;
import com.ymk.core.code.cmd.MemberCmdCode;
import com.ymk.core.code.cmd.OrdersCmdCode;
import com.ymk.core.code.cmd.PayPaymentCmdCode;
import com.ymk.core.code.req.ReqCode;
import com.ymk.core.constants.SysConstants;
import com.ymk.core.enums.member.MemberFinanceBizTypeEnum;
import com.ymk.core.enums.orders.OrdersStatusEnum;
import com.ymk.core.enums.pay.PayDivideStatusEnum;
import com.ymk.core.enums.pay.PayDivideTypeEnum;
import com.ymk.core.enums.pay.PayStatusEnum;
import com.ymk.core.enums.pay.PayTypeEnum;
import com.ymk.mq.MessageSender;
import com.ymk.service.IPayDivideService;
import com.ymk.service.IPayPaymentService;
import com.ymk.service.WxService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Objects;

@Service
public class PayPaymentPostCmd extends ACmd {

    @Override
    public CmdSign executeMop(HttpServletRequest request, CmdSign sign) throws Exception {
        CmdSign respSign = new CmdSign(sign);
        PayPaymentBO reqData = super.getData(sign, PayPaymentBO.class);


        MemberBO member = this.schedulerFacade.getMember(reqData.getMemberId(), sign);
        if (SysConstants.YES.equals(member.getIsVip())) {
            throw new MallException("请先加入会员！");
        }

        PayPaymentBO payPaymentBO = new PayPaymentBO();
        payPaymentBO.setMchId(sign.getMchId());
        payPaymentBO.setPayNo(IdUtil.simpleUUID());
        payPaymentBO.setMemberId(reqData.getMemberId());
        payPaymentBO.setStatus(PayStatusEnum.SUCCESS.getStatus());
        payPaymentBO.setPayDate(new Date());

        payPaymentBO.setOrdersId(reqData.getOrdersId());
        if (PayTypeEnum.POINT_RECHARGE.getType().equals(reqData.getPayType())) {

            payPaymentBO.setPayType(PayTypeEnum.POINT_RECHARGE.getType());
            payPaymentBO.setOrdersId(0);
            payPaymentBO.setRemark("积分充值");
            payPaymentBO.setAmount(reqData.getAmount());

        } else if (PayTypeEnum.CASH_PAY.getType().equals(reqData.getPayType())) {
            payPaymentBO.setPayType(PayTypeEnum.CASH_PAY.getType());
            payPaymentBO.setRemark("现金支付");

            ParamsBuilder paramsBuilder = ParamsBuilder.newBuild()
                    .addParam("id", reqData.getOrdersId())
                    .addParam("loadItem", true);
            CmdSign ordersCmd = CmdSign.Builder.newBuild(sign)
                    .setSource(paramsBuilder.build())
                    .setCmdCode(OrdersCmdCode.ORDERS_GET)
                    .setScope(SysConstants.CMD_SERVER_SCOPE)
                    .build();
            OrdersBO dbOrdersBO = this.scheduler.schedule(request, ordersCmd, OrdersBO.class);
            if (Objects.isNull(dbOrdersBO.getId())) {
                throw new MallException("订单不存在");
            }
            if (!OrdersStatusEnum.UNPAID.getStatus().equals(dbOrdersBO.getStatus())) {
                throw new MallException("订单已付款");
            }
            payPaymentBO.setAmount(dbOrdersBO.getOrdersAmount());

        } else {
            throw new MallException("支付业务异常!");
        }

        super.setCreatedData(sign, payPaymentBO);
        this.payPaymentService.post(payPaymentBO);

        // 积分充值
        if (PayTypeEnum.POINT_RECHARGE.getType().equals(reqData.getPayType())) {

            // 生成财务表
            MemberFinanceLogBO memberFinanceLogBO = new MemberFinanceLogBO();
            memberFinanceLogBO.setMchId(sign.getMchId());
            memberFinanceLogBO.setMemberId(reqData.getMemberId());
            memberFinanceLogBO.setBizType(MemberFinanceBizTypeEnum.GIVE_PRESENT.getType());
            memberFinanceLogBO.setBizId(payPaymentBO.getId());
            memberFinanceLogBO.setChangeAmount(reqData.getAmount());
            memberFinanceLogBO.setRemark("积分充值");
            super.setCreatedData(sign, memberFinanceLogBO);

            CmdSign financeLogPostCmd = CmdSign.Builder.newBuild(sign)
                    .setSource(memberFinanceLogBO)
                    .setCmdCode(MemberCmdCode.MEMBER_FINANCE_LOG_POST)
                    .setScope(SysConstants.CMD_SERVER_SCOPE)
                    .build();
            MemberFinanceLogBO dbFinanceLogBO = this.scheduler.schedule(request, financeLogPostCmd, MemberFinanceLogBO.class);

            // 生成分账信息
            payPaymentBO.setFinanceLogId(dbFinanceLogBO.getId());
            this.savePayDivide(request, sign, payPaymentBO, PayDivideTypeEnum.GIVE_PRESENT.getType());
            // 同步会员积分
            this.messageSender.sendMemberFinanceSync(reqData.getMemberId(), sign);

        } else if (PayTypeEnum.CASH_PAY.getType().equals(reqData.getPayType())) {

            // 生成分账信息
            PayDivideBO payDivideBO = this.savePayDivide(request, sign, payPaymentBO, PayDivideTypeEnum.PLACE_ORDER.getType());

            // 同步订单信息
            OrdersBO editOrdersBO = new OrdersBO();
            editOrdersBO.setId(payPaymentBO.getOrdersId());
            editOrdersBO.setPaymentId(payPaymentBO.getId());
            editOrdersBO.setPayType(PayTypeEnum.CASH_PAY.getType());
            editOrdersBO.setSuperiorAmount(payDivideBO.getDivideAmount());
            BigDecimal profitAmount = payDivideBO.getPayAmount().subtract(payDivideBO.getDivideAmount());
            editOrdersBO.setProfitAmount(profitAmount);
            editOrdersBO.setStatus(OrdersStatusEnum.SUCCESS.getStatus());

            CmdSign ordersPatchCmd = CmdSign.Builder.newBuild(sign)
                    .setSource(editOrdersBO)
                    .setCmdCode(OrdersCmdCode.ORDERS_PATCH)
                    .setReqCode(ReqCode.PAY_SYNC_ORDERS)
                    .setScope(SysConstants.CMD_SERVER_SCOPE)
                    .build();
            this.scheduler.schedule(request, ordersPatchCmd);
        }

        return respSign;
    }

    @Override
    public CmdSign executeStore(HttpServletRequest request, CmdSign sign) throws Exception {
        CmdSign respSign = new CmdSign(sign);
        PayPaymentBO reqData = super.getData(sign, PayPaymentBO.class);

        ParamsBuilder paramsBuilder = ParamsBuilder.newBuild()
                .addParam("id", reqData.getOrdersId())
                .addParam("loadItem", true);
        CmdSign ordersCmd = CmdSign.Builder.newBuild(sign)
                .setSource(paramsBuilder.build())
                .setCmdCode(OrdersCmdCode.ORDERS_GET)
                .setScope(SysConstants.CMD_SERVER_SCOPE)
                .build();
        OrdersBO dbOrdersBO = this.scheduler.schedule(request, ordersCmd, OrdersBO.class);
        if (Objects.isNull(dbOrdersBO.getId())) {
            throw new MallException("订单不存在");
        }
        if (!OrdersStatusEnum.UNPAID.getStatus().equals(dbOrdersBO.getStatus())) {
            throw new MallException("订单已付款");
        }

        PayPaymentBO payPaymentBO = new PayPaymentBO();
        payPaymentBO.setMchId(sign.getMchId());
        payPaymentBO.setPayNo(IdUtil.simpleUUID());
        payPaymentBO.setMemberId(sign.getUserId());
        payPaymentBO.setOrdersId(dbOrdersBO.getId());
        payPaymentBO.setAmount(dbOrdersBO.getOrdersAmount());
        payPaymentBO.setPayType(reqData.getPayType());
        payPaymentBO.setStatus(PayStatusEnum.UNPAID.getStatus());

        // 积分支付
        if (PayTypeEnum.INTEGRAL_PAY.getType().equals(payPaymentBO.getPayType())) {
            payPaymentBO.setPayType(PayTypeEnum.INTEGRAL_PAY.getType());
            payPaymentBO.setStatus(PayStatusEnum.SUCCESS.getStatus());
        } else {
            // 微信支付
            MchBO mchBO = this.schedulerFacade.getMch(request, sign.getMchId());
            payPaymentBO = this.wxService.wxPay(sign, mchBO, payPaymentBO);
            payPaymentBO.setPayType(PayTypeEnum.WX_PAY.getType());
        }
        super.setCreatedData(sign, payPaymentBO);
        this.payPaymentService.post(payPaymentBO);

        // 积分支付
        if (PayTypeEnum.INTEGRAL_PAY.getType().equals(payPaymentBO.getPayType())) {
            MemberBO member = this.schedulerFacade.getMember(sign.getUserId(), sign);
            if (SysConstants.YES.equals(member.getIsVip())) {
                throw new MallException("请先加入会员！");
            }
            if (member.getPoints().compareTo(dbOrdersBO.getOrdersAmount()) < 0) {
                throw new MallException("积分不足");
            }

            // 生成财务表
            MemberFinanceLogBO memberFinanceLogBO = new MemberFinanceLogBO();
            memberFinanceLogBO.setMchId(sign.getMchId());
            memberFinanceLogBO.setMemberId(sign.getUserId());
            memberFinanceLogBO.setBizType(MemberFinanceBizTypeEnum.PLACE_ORDER.getType());
            memberFinanceLogBO.setBizId(payPaymentBO.getId());
            memberFinanceLogBO.setChangeAmount(payPaymentBO.getAmount().negate());
            memberFinanceLogBO.setRemark("订单支付");
            super.setCreatedData(sign, memberFinanceLogBO);

            CmdSign financeLogPostCmd = CmdSign.Builder.newBuild(sign)
                    .setSource(memberFinanceLogBO)
                    .setCmdCode(MemberCmdCode.MEMBER_FINANCE_LOG_POST)
                    .setScope(SysConstants.CMD_SERVER_SCOPE)
                    .build();
            this.scheduler.schedule(request, financeLogPostCmd);
            this.messageSender.sendMemberFinanceSync(reqData.getMemberId(), sign);

            //生成分账信息
            PayDivideBO payDivideBO = this.savePayDivide(request, sign, payPaymentBO, PayDivideTypeEnum.PLACE_ORDER.getType());
            // 修改订单信息
            OrdersBO editOrdersBO = new OrdersBO();
            editOrdersBO.setId(payPaymentBO.getOrdersId());
            editOrdersBO.setPaymentId(payPaymentBO.getId());
            editOrdersBO.setPayType(PayTypeEnum.INTEGRAL_PAY.getType());
            editOrdersBO.setSuperiorAmount(payDivideBO.getDivideAmount());
            BigDecimal profitAmount = payDivideBO.getPayAmount().subtract(payDivideBO.getDivideAmount());
            editOrdersBO.setProfitAmount(profitAmount);
            editOrdersBO.setStatus(OrdersStatusEnum.SUCCESS.getStatus());

            CmdSign ordersPatchCmd = CmdSign.Builder.newBuild(sign)
                    .setSource(editOrdersBO)
                    .setCmdCode(OrdersCmdCode.ORDERS_PATCH)
                    .setReqCode(ReqCode.PAY_SYNC_ORDERS)
                    .setScope(SysConstants.CMD_SERVER_SCOPE)
                    .build();
            this.scheduler.schedule(request, ordersPatchCmd);

            return respSign;
        }

        respSign.setSource(super.getSource(JSON.parseObject(payPaymentBO.getReqData()).getJSONObject("payment")));
        return respSign;
    }

    private PayDivideBO savePayDivide(HttpServletRequest request, CmdSign sign, PayPaymentBO payPaymentBO, String bizType) throws Exception {
        // 生成分账信息
        PayDivideBO payDivideBO = new PayDivideBO();
        payDivideBO.setMchId(payPaymentBO.getMchId());
        payDivideBO.setMemberId(payPaymentBO.getMemberId());
        payDivideBO.setBizId(PayDivideTypeEnum.GIVE_PRESENT.getType().equals(bizType)?payPaymentBO.getFinanceLogId():payPaymentBO.getOrdersId());
        payDivideBO.setBizType(bizType);
        payDivideBO.setPayPaymentId(payPaymentBO.getId());
        payDivideBO.setPayAmount(payPaymentBO.getAmount());
        payDivideBO.setStatus(PayDivideStatusEnum.DIVIDE_SUCCESS.getStatus());
        MchBO dbMch = this.schedulerFacade.getMch(request, sign.getMchId());
        if (Objects.isNull(dbMch) || Objects.isNull(dbMch.getId())) {
            throw new MallException("分账时商户异常!");
        }
        BigDecimal divideAmount = payPaymentBO.getAmount().multiply(dbMch.getDivideRatio());
        payDivideBO.setDivideAmount(divideAmount);
        super.setCreatedData(sign, payDivideBO);
        this.payDivideService.post(payDivideBO);
        return payDivideBO;
    }


    @Override
    public CmdSign verify(HttpServletRequest request, CmdSign sign) throws Exception {
        PayPaymentBO payPaymentBO = super.getData(sign, PayPaymentBO.class);
        if (Objects.isNull(payPaymentBO.getOrdersId()) && !PayTypeEnum.POINT_RECHARGE.getType().equals(payPaymentBO.getPayType())) {
            throw new MallException("订单id为空");
        }
        return null;
    }

    @Override
    public String getCmdCode() {
        return PayPaymentCmdCode.PAY_PAYMENT_POST;
    }

    @Autowired
    private IPayPaymentService payPaymentService;
    @Autowired
    private IPayDivideService payDivideService;
    @Autowired
    private WxService wxService;
    @Autowired
    private MessageSender messageSender;
}